#include <iostream>
#include <etcd/Client.hpp>
#include <etcd/Response.hpp>
#include <etcd/Value.hpp>
#include <etcd/Watcher.hpp>
#include <thread>

/*
    使用etcd-cpp-apiv3库来访问etcd服务，测试etcd服务的发现功能
*/

void callback(const etcd::Response &resp)
{
    if (!resp.is_ok())
    {
        std::cout << "事件通知错误\n";
        return;
    }
    etcd::Events ev = resp.events(); // 返回监听到的事件
    for (auto &e : ev)
    {
        if (e.event_type() == etcd::Event::EventType::PUT)
        {
            if (e.prev_kv().key() == "")
            {
                std::cout << "<新增>\n";
                std::cout << "数据值：" << e.kv().key() << "-" << e.kv().as_string() << std::endl;
            }
            else
            {
                cout << "<修改>\n";
                std::cout << "原来的值：" << e.prev_kv().key() << "-" << e.prev_kv().as_string() << std::endl;
                std::cout << "当前的值：" << e.kv().key() << "-" << e.kv().as_string() << std::endl;
            }
        }
        else if (e.event_type() == etcd::Event::EventType::DELETE_)
        {
            cout << "<删除>\n";
            std::cout << "原来的值：" << e.prev_kv().key() << "-" << e.prev_kv().as_string() << std::endl;
        }
    }
}

int main()
{
    // 1、创建客户端
    const std::string etcd_url = "http://127.0.0.1:2379";
    etcd::Client client(etcd_url);

    // 2、访问etcd服务获取 && 发现数据
    pplx::task<etcd::Response> task_response = client.ls("/services");
    etcd::Response resp = task_response.get();
    if (resp.is_ok() == false)
    {
        std::cout << "ls数据错误:" << resp.error_message() << "\n";
        return -1;
    }

    // 3、打印获得的数据
    size_t sz = resp.keys().size(); // 数据个数
    for (int i = 0; i < sz; i++)
    {
        // 下面两种方式都可以
        std::cout << resp.value(i).as_string() << "提供服务：" << resp.key(i) << std::endl;
        // std::cout << resp.value(i).as_string() << "提供服务：" << resp.value(i).key() << std::endl;
    }

    // 4、创建键值对监控对象
    // callback:发生时间后的回调，true:递归监控"/services"下的所有key
    etcd::Watcher watcher(client, "/services", callback, true); //对象创建成功即开始监听
    watcher.Wait(); //一直等待，直到取消watcher

    return 0;
}